// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose:  Definition of CUpdateChecker class..
//   $Id$


#pragma once

#include <wininet.h>

class CUpdateChecker
{
public:
	// Construction.
	CUpdateChecker();

	// Destruction.
	~CUpdateChecker();

	// Initialisation.
	HRESULT Initialise(BSTR sCurrentVersion);

	// Check for updates.
	HRESULT CheckForUpdates(void);

	static DWORD WINAPI ThreadCheckForUpdates(LPVOID pParameter);

	// Download and install updates, pending agreement from the user.
	HRESULT RequestInstall(void);

protected:

private:
	CUpdateChecker(const CUpdateChecker &rhs);
	CUpdateChecker &operator=(const CUpdateChecker &rhs);

	static inline bool IsInternetConnectionOpen(void);
	static inline bool IsDataUnicode(const void *pData);
	static inline bool IsVersionOlder(const BSTR sSubject, const BSTR sObject);
	static inline void ParseVersionString(const BSTR sVersion, int &nVersionPart, int &nMajorRevPart, int &nMinorRevPart, int &nBuildRevPart);

	bool m_bInitialised, m_bUpdatesAvailable, m_bInstallationInProgress;
	CComBSTR m_sCurrentVersion;
};

inline bool CUpdateChecker::IsInternetConnectionOpen(void)
{
	DWORD dwConnectionFlags = 0;

	if(InternetGetConnectedState(&dwConnectionFlags, 0) == FALSE || dwConnectionFlags & INTERNET_CONNECTION_OFFLINE)
		return false;

	return true;
}

inline bool CUpdateChecker::IsDataUnicode(const void *pData)
{
	if(pData && ((reinterpret_cast<const char *>(pData)[0] == 0xff && reinterpret_cast<const char *>(pData)[1] == 0xfe) || (reinterpret_cast<const char *>(pData)[0] == 0xfe && reinterpret_cast<const char *>(pData)[1] == 0xff)))
		return true;

	return false;
}

inline bool CUpdateChecker::IsVersionOlder(const BSTR sSubject, const BSTR sObject)
{
	int nSubjectV, nSubjectMa, nSubjectMi, nSubjectB;
	ParseVersionString(sSubject, nSubjectV, nSubjectMa, nSubjectMi, nSubjectB);

	int nObjectV, nObjectMa, nObjectMi, nObjectB;
	ParseVersionString(sObject, nObjectV, nObjectMa, nObjectMi, nObjectB);

	bool bSubjectIsOlderThanObject = false;

	if(nObjectV != -1) {
		if(nSubjectV < nObjectV)
			bSubjectIsOlderThanObject = true;
		else if(nSubjectV == nObjectV && nObjectMa != -1) {
			if(nSubjectMa < nObjectMa)
				bSubjectIsOlderThanObject = true;
			else if(nSubjectMa == nObjectMa && nObjectMi != -1) {
				if(nSubjectMi < nObjectMi)
					bSubjectIsOlderThanObject = true;
				else if(nSubjectMi == nObjectMi && nObjectB != -1 && nSubjectMi < nObjectMi)
					bSubjectIsOlderThanObject = true;
			}
		}
	}

	return bSubjectIsOlderThanObject;
}

inline void CUpdateChecker::ParseVersionString(const BSTR sVersion, int &nVersionPart, int &nMajorRevPart, int &nMinorRevPart, int &nBuildRevPart)
{
	nVersionPart = nMajorRevPart = nMinorRevPart = nBuildRevPart = -1;

	if(sVersion) {
		wchar_t *p1 = wcschr(const_cast<BSTR>(sVersion), L'.');
		if(p1) {
			*p1 = L'\0';
			nVersionPart = _wtoi(const_cast<BSTR>(sVersion));
			*p1++ = L'.';
			wchar_t *p2 = wcschr(p1, L'.');
			if(p2) {
				*p2 = L'\0';
				nMajorRevPart = _wtoi(p1);
				*p2++ = L'.';
				wchar_t *p3 = wcschr(p2, L'.');
				if(p3) {
					*p3 = L'\0';
					nMinorRevPart = _wtoi(p2);
					*p3++ = L'.';
					nBuildRevPart = _wtoi(p3);
				} else
					nMinorRevPart = _wtoi(p2);
			} else
				nMajorRevPart = _wtoi(p1);
		} else
			nVersionPart = _wtoi(sVersion);
	}
}
